#include <iostream>
#include <string>
#include <sstream>
#include <fstream>
#include <cstring>
#include "../logic_layer/external_sort/DictionaryTerm.h"
#include "../logic_layer/external_sort/DictionaryTermsFile.h"
#include "../logic_layer/bplustree/BPlusTreeTemplate.h"
#include "../logic_layer/bplustree/bplusfilehandler/BPlusTreeFile.h"

using std::cout;
using std::endl;
using std::string;

#define MAX_CICLES 25
#define DEBUG

typedef std::shared_ptr<DictionaryTerm> DictionaryTerm_sptr;

bool truncTree = false;
string inputFile = "";
bool inputWithRandomKey = false;
size_t blockSize = 8 * 64, maxCycles = 0;
bool fullIndex = true;
string listOutputFile = "";
bool preorderReport = false;

void invalid_args() {
	std::cerr << "Argumentos inválidos. " << std::endl
			<< "Uso: app treeFile [ -l <DictionaryTermsFile> [ -i | -M <magicNumber> | -max <limitEntries> ] | -list <outputFileName> | -preorderReport ]"
			<< std::endl;
	exit(1);
}

void parseArgs(int argc, char* argv[]) {

	for (int i = 2; i < argc; ++i) {
		if (strcmp(argv[i], "-l") == 0) {
			inputFile = string(argv[i + 1]);
			truncTree = true;
			i++;
			continue;
		}
		if (strcmp(argv[i], "-i") == 0) {
			if (!truncTree)
				invalid_args();
			inputWithRandomKey = true;
			continue;
		}
		if (strcmp(argv[i], "-M") == 0) {
			if (!truncTree)
				invalid_args();

			blockSize = atoi(argv[i + 1]);
			blockSize *= 64;

			if (blockSize <= 0)
				invalid_args();

			i++;
			continue;
		}
		if (strcmp(argv[i], "-max") == 0) {
			if (!truncTree)
				invalid_args();

			maxCycles = atoi(argv[i + 1]);

			if (maxCycles <= 0)
				invalid_args();

			fullIndex = false;
			i++;
			continue;
		}
		if (strcmp(argv[i], "-list") == 0) {
			listOutputFile = string(argv[i + 1]);
			i++;
			continue;
		}
		if (strcmp(argv[i], "-preorderReport") == 0) {
			preorderReport = true;
			continue;
		}
	}
}

void PRINT_STATUSBAR(unsigned int currentValue, unsigned int total) {
	if (currentValue == 1) {
		cout << "| 0% ---";
		fflush(stdout);
	}
	if (currentValue == (int) (total / 10)) {
		cout << " 10% ---";
		fflush(stdout);
	}
	if (currentValue == (int) (2 * total / 10)) {
		cout << " 20% ---";
		fflush(stdout);
	}
	if (currentValue == (int) (3 * total / 10)) {
		cout << " 30% ---";
		fflush(stdout);
	}
	if (currentValue == (int) (4 * total / 10)) {
		cout << " 40% ---";
		fflush(stdout);
	}
	if (currentValue == (int) (5 * total / 10)) {
		cout << " 50% ---";
		fflush(stdout);
	}
	if (currentValue == (int) (6 * total / 10)) {
		cout << " 60% ---";
		fflush(stdout);
	}
	if (currentValue == (int) (7 * total / 10)) {
		cout << " 70% ---";
		fflush(stdout);
	}
	if (currentValue == (int) (8 * total / 10)) {
		cout << " 80% ---";
		fflush(stdout);
	}
	if (currentValue == (int) (9 * total / 10)) {
		cout << " 90% ---";
		fflush(stdout);
	}
	if (currentValue == (int) (total - 1)) {
		cout << " 100% --- | Done!\n";
		fflush(stdout);
	}
}

int main(int argc, char *argv[]) {

	if (argc < 2)
		invalid_args();

	parseArgs(argc, argv);

	BPlusTreeFile treeFileHandler(string(argv[1]), blockSize, truncTree);

	BPlusTreeTemplate<DTRkey_t, DTRvalue_t, keyComparator_func> tree(
			&treeFileHandler);

	if(preorderReport){

		tree.MostrarContenidoReducido();

		return 0;

	}

	if (truncTree) {

#ifdef DEBUG
		ofstream listIn("list.in");
#endif

		LeafRegister_ptr temp_ptr;
		unsigned int count = 0;
		string key;
		size_t size = 100;

		DictionaryTermsFile dictionaryInput(inputFile.c_str(), ios_base::in,
				size, size, inputWithRandomKey);

		while ((fullIndex || count < maxCycles) && dictionaryInput.hasNext()) {
			DictionaryTerm_sptr term = dictionaryInput.get();

			key = string(term->getTerm());

			if (key.find("ñ", 0) == string::npos) {

#ifdef DEBUG
				listIn << key << endl;
#endif
				temp_ptr.reset(new LeafRegister_t(key, { count, 0 }));

				if (fullIndex == false)
					PRINT_STATUSBAR(count, maxCycles);

				tree.InsertRegister(temp_ptr);

				count++;
			}
		}

		dictionaryInput.close();

#ifdef DEBUG

		listIn.close();
#endif

	}

	if (!listOutputFile.empty()) {

		ofstream listOut(listOutputFile);
		DTRkey_t first("a");

		searchResult_t resultado = tree.SearchRegister(first);

		//testTree.SearchNextRegister(resultado);

		while (resultado.valid) {
			listOut << resultado.result->getKey() << endl;
			resultado = tree.SearchNextRegister(resultado);
		}

		listOut << resultado.result->getKey() << endl;
		listOut.close();

	}

	return 0;
}

